package cn.tedu.qxhouserent.house.service.impl;

import cn.tedu.qxhouserent.commons.pojo.vo.PageData;
import cn.tedu.qxhouserent.commons.web.ServiceCode;
import cn.tedu.qxhouserent.commons.ex.ServiceException;
import cn.tedu.qxhouserent.house.mapper.UserMapper;
import cn.tedu.qxhouserent.house.mapper.UserHouseCollectionMapper;
import cn.tedu.qxhouserent.house.mapper.UserHouseAppointMapper;
import cn.tedu.qxhouserent.house.mapper.UserHouseScanMapper;
import cn.tedu.qxhouserent.house.mapper.UserHouseCommentMapper;
import cn.tedu.qxhouserent.house.mapper.UserNewsCollectionMapper;
import cn.tedu.qxhouserent.house.mapper.UserNewsCommentMapper;
import cn.tedu.qxhouserent.house.mapper.UserNewsScanMapper;
import cn.tedu.qxhouserent.house.pojo.entity.User;
import cn.tedu.qxhouserent.house.pojo.param.UserAddNewParam;
import cn.tedu.qxhouserent.house.pojo.param.UserLoginInfoParam;
import cn.tedu.qxhouserent.house.pojo.param.UserUpdateInfoParam;
import cn.tedu.qxhouserent.house.pojo.vo.*;
import cn.tedu.qxhouserent.house.service.UserService;
import cn.tedu.qxhouserent.commons.util.PageInfoToPageDataConverter;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mysql.cj.protocol.x.XMessage;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.net.Authenticator;
import java.time.LocalDateTime;
import java.util.*;

import static cn.tedu.qxhouserent.commons.web.ServiceCode.*;


@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserHouseCollectionMapper userHouseCollectionMapper;

    @Autowired
    private UserHouseAppointMapper userHouseAppointMapper;

    @Autowired
    private UserHouseScanMapper userHouseScanMapper;

    @Autowired
    private UserHouseCommentMapper userHouseCommentMapper;

    @Autowired
    private UserNewsCollectionMapper userNewsCollectionMapper;

    @Autowired
    private UserNewsCommentMapper userNewsCommentMapper;

    @Autowired
    private UserNewsScanMapper userNewsScanMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("${qxhouserent.jwt.secret-key}")
    private String secretKey;

    @Value("${qxhouserent.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Override
    public void addNew(UserAddNewParam userAddNewParam) {
        log.debug("开始处理【添加用户】的业务，参数：{}", userAddNewParam);
        // 检查用户名是否被占用,如果被占用,则抛出异常
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",userAddNewParam.getUsername());
        Integer countByUsername = userMapper.selectCount(queryWrapper);
        log.debug("根据用户名统计匹配的用户数量，结果：{}", countByUsername);
        if (countByUsername > 0){
            String message = "添加用户失败,用户名已经被占用!";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 检查用户昵称是否被占用,如果被占用,则抛出异常
        QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("nickname",userAddNewParam.getNickname());
        Integer countByNickname = userMapper.selectCount(queryWrapper2);
        log.debug("根据用户昵称统计匹配的用户数量，结果：{}", countByNickname);
        if (countByNickname > 0){
            String message = "添加用户失败,用户昵称已经被占用!";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 检查用户电话号是否被占用,如果被占用,则抛出异常
        QueryWrapper<User> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("phone_number",userAddNewParam.getPhoneNumber());
        Integer countByPhoneNumber = userMapper.selectCount(queryWrapper3);
        log.debug("根据电话号码统计匹配的用户数量，结果：{}", countByPhoneNumber);
        if (countByPhoneNumber > 0){
            String message = "添加用户失败,电话号码已经被占用!";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 检查用户邮箱是否被占用,如果被占用,则抛出异常
        QueryWrapper<User> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("email",userAddNewParam.getEmail());
        Integer countByEmail = userMapper.selectCount(queryWrapper4);
        log.debug("根据邮箱统计匹配的用户数量，结果：{}", countByEmail);
        if (countByEmail > 0){
            String message = "添加用户失败,邮箱已经被占用!";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        User user = new User();
        BeanUtils.copyProperties(userAddNewParam,user);
        String encodedPassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodedPassword);
        user.setGmtCreate(LocalDateTime.now());
        user.setGmtModified(LocalDateTime.now());
        log.debug("准备将新的用户数据写入到数据库，数据：{}", user);
        int rows = userMapper.insert(user);
        if (rows != 1){
            String message = "添加用户失败,服务器正忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ERR_INSERT,message);
        }
        log.debug("将新的用户数据写入到数据库，完成！");

    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【通过id删除用户】的业务，参数：{}" ,id);

        // 检查用户是否存在，如果不存在，则抛出异常
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",id);
        int countById = userMapper.selectCount(queryWrapper);
        log.debug("根据用户id统计匹配的用户数量，结果：{}" , countById);
        if (countById==0){
            String message = "删除用户失败，用户数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        int rows = userMapper.deleteById(id);
        if (rows != 1){
            String message = "删除用户失败,服务器正忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ERR_DELETE,message);
        }

        //判断是否有用户收藏房源关联到用户表上,如果有关联数据一起删除
        List<Long> userHouseCollectionIds = userHouseCollectionMapper.getUserHouseCollectionIds(id);
        for (Long userHouseCollectionId : userHouseCollectionIds){
            int i = userHouseCollectionMapper.deleteById(userHouseCollectionId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户预约看房信息关联到用户表上,如果有关联数据一起删除
        List<Long> userHouseAppointIds = userHouseAppointMapper.getUserHouseAppointIds(id);
        for (Long userHouseAppointId : userHouseAppointIds){
            int i = userHouseAppointMapper.deleteById(userHouseAppointId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户浏览房源信息关联到用户表上,如果有关联数据一起删除
        List<Long> userHouseScanIds = userHouseScanMapper.getUserHouseScanIds(id);
        for (Long userHouseScanId : userHouseScanIds){
            int i = userHouseScanMapper.deleteById(userHouseScanId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户房源评论信息关联到用户表上,如果有关联数据一起删除
        List<Long> userHouseCommentIds = userHouseCommentMapper.getUserHouseCommentIds(id);
        for (Long userHouseCommentId : userHouseCommentIds){
            int i = userHouseCommentMapper.deleteById(userHouseCommentId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户和收藏资讯信息关联到用户表上,如果有关联数据一起删除
        List<Long> userNewsCollectionIds = userNewsCollectionMapper.getUserNewsCollectionIds(id);
        for (Long userNewsCollectionId : userNewsCollectionIds){
            int i = userNewsCollectionMapper.deleteById(userNewsCollectionId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户和评论信息关联到用户表上,如果有关联数据一起删除
        List<Long> userNewsCommentIds = userNewsCommentMapper.getUserNewsCommentIds(id);
        for (Long userNewsCommentId : userNewsCommentIds){
            int i = userNewsCommentMapper.deleteById(userNewsCommentId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //判断是否有用户和浏览资讯信息关联到用户表上,如果有关联数据一起删除
        List<Long> userNewsScanIds = userNewsScanMapper.getUserNewsScanIds(id);
        for (Long userNewsScanId : userNewsScanIds){
            int i = userNewsScanMapper.deleteById(userNewsScanId);
            if (i < 1){
                String message = "删除用户失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }


        log.debug("将用户数据从数据库中删除，完成！");

    }


    @Override
    public UserStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询用户】的业务，参数：{}", id);
        UserStandardVO queryResult = userMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "查询用户详情失败，数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    @Override
    public void updateById(Long id, UserUpdateInfoParam userUpdateInfoParam) {
        log.debug("开始处理【修改用户详情】业务：{}", userUpdateInfoParam);

        // 检查用户详情是否存在，如果不存在，则抛出异常
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id",id);
        int countById = userMapper.selectCount(queryWrapper);
        log.debug("根据用户ID统计匹配的用户数量，结果：{}", countById);
        if (countById==0){
            String message = "修改用户失败，用户数据不存在！";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND, message);
        }

        //查看用户名是否已存在,如果存在,则抛出异常
        QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("username", userUpdateInfoParam.getUsername())
                .ne("id", id);
        Integer countByUsername = userMapper.selectCount(queryWrapper2);
        if (countByUsername > 0) {
            String message = "用户中有相同用户名的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }

        //查看用户昵称是否已存在,如果存在,则抛出异常
        QueryWrapper<User> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("nickname", userUpdateInfoParam.getNickname())
                .ne("id", id);
        Integer countByNickname = userMapper.selectCount(queryWrapper3);
        if (countByNickname > 0) {
            String message = "用户中有相同用户昵称的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }

        //查看用户电话是否已存在,如果存在,则抛出异常
        QueryWrapper<User> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.eq("phone_number", userUpdateInfoParam.getPhoneNumber())
                .ne("id", id);
        Integer countByPhoneNumber = userMapper.selectCount(queryWrapper4);
        if (countByNickname > 0) {
            String message = "用户中有相同电话的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }

        //查看用户邮箱是否已存在,如果存在,则抛出异常
        QueryWrapper<User> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.eq("email", userUpdateInfoParam.getEmail())
                .ne("id", id);
        Integer countByEmail = userMapper.selectCount(queryWrapper5);
        if (countByNickname > 0) {
            String message = "用户中有相同邮箱的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }
        // 执行用户表修改
        User user = new User();
        BeanUtils.copyProperties(userUpdateInfoParam,user);
        user.setGmtModified(LocalDateTime.now());
        user.setId(id);
        userMapper.updateById(user);
        log.debug("将新的用户数据更新入到数据库，完成！");

    }


    @Override
    public PageData<UserListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum,pageSize);
    }

    @Override
    public PageData<UserListItemVO> list(Integer pageNum, Integer pageSize) {
        log.debug("开始处理【查询用户列表】的业务，页码：{}，每页记录数：{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<UserListItemVO> list = userMapper.list();
        PageInfo<UserListItemVO> pageInfo = new PageInfo<>(list);
        PageData<UserListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("查询完成，即将返回：{}", pageData);
        return pageData;
    }

    @Override
    public String login(UserLoginInfoParam userLoginInfoParam) {
        log.debug("开始处理【用户登录】的业务，参数：{}",userLoginInfoParam);

        UserStandardVO standardByUsername = userMapper.getStandardByUsername(userLoginInfoParam.getUsername());
        if (standardByUsername == null || !standardByUsername.getPassword().equals(userLoginInfoParam.getPassword())) {
            String message = "用户名或密码错误！";
            log.debug(message);
            throw new ServiceException(ERR_NOT_FOUND, message);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put("id",standardByUsername.getId());
        claims.put("username",standardByUsername.getUsername());

        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                //Payload
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000))
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                //生成
                .compact();

        log.debug("生成了用户信息对应的JWT: {}",jwt);
        return jwt;
    }
}
